package com.itheima.stock.security.config;

import com.itheima.stock.security.filter.JwtAuthorizationFilter;
import com.itheima.stock.security.filter.JwtLoginAuthenticationFilter;
import com.itheima.stock.security.handler.StockAccessDeniedHandler;
import com.itheima.stock.security.handler.StockAuthenticationFilterEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @author by itheima
 * @Date 2022/1/22
 * @Description
 */
@Configuration
@EnableWebSecurity//开启webSecurity安全设置生效
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启security pre/post注解的使用
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * IOC容器中存在加密处理的bean，则自行调用
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    private String[] getPubPath(){
        //公共访问资源
        String[] urls={
                "/**/*.css","/**/*.js","/favicon.ico","/doc.html",
                "/druid/**","/webjars/**","/v2/api-docs","/api/captcha",
                "/swagger/**","/swagger-resources/**","/swagger-ui.html"
        };
        return urls;
    }


    /**
     * 封装用户登录时，获取用户明细信息的服务bean
     * @return
     */
//    @Bean
//    public UserDetailsService inMemoryUserDetailsManager(){
//        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
//        //在内存中构建用户信息
////        new User("zhangsan","{noop}666", )
//        UserDetails user1 = User.withUsername("zhangsan").password("$2a$10$svZomA/7n27re.C7cBbYjuat1Fvs4RbgJif5Hk9iCCSY6ahhdVe4S").authorities("P5", "ROLE_ADMIN").build();
//        UserDetails user2 = User.withUsername("lisi").password("$2a$10$b6lLDLfa0grGEQeene.sbuobjSq3NBjGppKwN3AhGTJJO.jfs6SrG").authorities("P8", "ROLE_CEO").build();
////        UserDetails user1 = User.withUsername("zhangsan").password("{noop}666").authorities("P5", "ROLE_ADMIN").build();
////        UserDetails user2 = User.withUsername("lisi").password("{noop}888").authorities("P8", "ROLE_CEO").build();
//        userDetailsManager.createUser(user1);
//        userDetailsManager.createUser(user2);
//        return userDetailsManager;
//    }

    /**
     * 定义用户认证和授权的信息
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //登出功能，指定登出的url地址
        http.logout().logoutUrl("api/logout").invalidateHttpSession(true);
        //开启允许iframe 嵌套。 security默认使用ifram跨域与缓存
        http.headers().frameOptions().disable().cacheControl().disable();
        //session禁用
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.csrf().disable();//禁用跨域请求伪造

        http.authorizeRequests()//对资源进行认证处理
                .antMatchers(getPubPath()).permitAll()//公共资源都允许访问
                .anyRequest().authenticated();          //除了上述资源外，其他资源，只有认证通过后，才能有权访问
        //将自定义的过滤器加入security过滤器链，且在默认的认证过滤器之前执行
        http.addFilterBefore(jwtLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(jwtAuthorizationFilter(), JwtLoginAuthenticationFilter.class);
        http.exceptionHandling()
                .accessDeniedHandler(new StockAccessDeniedHandler())//配置资源访问拒绝处理器
                .authenticationEntryPoint(new StockAuthenticationFilterEntryPoint());

//        http.formLogin()//定义以表单方式登录
//                .loginPage("/login.html")//指定登录页面
//                .loginProcessingUrl("/api/login")
                //.defaultSuccessUrl("/index",true)//登录成功后默认跳转的路径,alwaysUse 表示只要认证成功，则必须跳转到index下
//                .failureUrl("/failue")
//                .successHandler(new LoginSuccessHandler())//自定义登录成功的处理器
//                .failureHandler(new LoginFailureHandler())//自定义登录失败的处理器
//                .and()
//                .logout()//登出使用默认的路径登出 /logout
//                .permitAll()//允许所有的用户访问登录或者登出的路径
//                .and()
//                .csrf().disable()//禁用csrf ：防止CSRF攻击
//                .authorizeRequests()//配置资源的访问权限
//                .antMatchers("/myLogin").permitAll()
//                .anyRequest().authenticated();
//                .antMatchers("/register").permitAll()//注册路径任意用户都允许
//                .antMatchers("/path1","/path2").hasAnyAuthority("per1","per2")//拥有指定的权限其一，即可访问指定的资源
                //拥有指定的j角色其一，即可访问指定的资源，指定的角色名称的前缀不能加ROLE_
//                .antMatchers("/path1","/path2").hasAnyRole("role1","role2")
//                .antMatchers("/index").hasIpAddress("192.168.23.10")//指定的ip才能访问指定的资源
//                .antMatchers("/hello").hasAuthority("P5")//设置hello路径资源只能被拥有P5权限的用户才能访问
//                .antMatchers("/say").hasRole("CEO")//拥有CEO角色的用户才能访问/say资源
//                .anyRequest().authenticated();
        //坑 ： 自定义的登录过滤器要在默认的登录过滤器之前执行，否则登录失败
//        http.addFilterBefore(jwtLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
//        http.exceptionHandling()
//                .accessDeniedHandler(new MyAccessDeniedHandler());//配置资源访问拒绝处理器
    }

    /**
     * 定义认证过滤器
     * @return
     * @throws Exception
     */
    @Bean
    public JwtLoginAuthenticationFilter jwtLoginAuthenticationFilter()  throws Exception{
        JwtLoginAuthenticationFilter authenticationFilter = new JwtLoginAuthenticationFilter("/api/login");
        //配置认证管理器
        authenticationFilter.setAuthenticationManager(authenticationManagerBean());
        //注入redis模板对象
        authenticationFilter.setRedisTemplate(redisTemplate);
        return authenticationFilter;
    }

    /**
     * 配置授权过滤器
     * @return
     */
    @Bean
    public JwtAuthorizationFilter jwtAuthorizationFilter(){
        return new JwtAuthorizationFilter();
    }

//    /**
//     * 定义登录拦截的bean
//     * @return
//     */
//    @Bean
//    public MyUserNamePasswordAuthenticationFilter myUserNamePasswordAuthenticationFilter() throws Exception {
//        //构造器中传入的是指定的默认登录地址
//        MyUserNamePasswordAuthenticationFilter myLoginFilter = new MyUserNamePasswordAuthenticationFilter("/api/login");
//        myLoginFilter.setAuthenticationManager(authenticationManagerBean());
//        return myLoginFilter;
//    }

}
